package com.mxx.common.utils;

import com.mxx.common.core.SFunction;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author: mxx
 * @date: 2021/8/12
 * @time: 11:15
 * @Description: 描述信息
 */
public class SFunctionUtil {


    public static <T, E> Object getFieldValue(Object dataSource, SFunction<T, E> function) {
        if (dataSource instanceof Map) {
            String fieldName = getFieldName(function);
            return ((Map) dataSource).get(fieldName);
        } else {
            try {
                String methodName = getMethodName(function);
                Method method = dataSource.getClass().getMethod(methodName);
                return method.invoke(dataSource);
            } catch (NoSuchMethodException | SecurityException ex) {
                throw new RuntimeException("方法不存在", ex);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static <T, E> String getMethodName(SFunction<T, E> function) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method writeReplace = function.getClass().getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);
        Object sl = writeReplace.invoke(function);
        SerializedLambda serializedLambda = (SerializedLambda) sl;
        String methodName = serializedLambda.getImplMethodName();
        return methodName;
    }

    public static <T, E> String getFieldName(SFunction<T, E> function) {
        try {
            String methodName = getMethodName(function);
            String fieldName = null;
            if (methodName.startsWith("get")) {
                byte[] bytes = methodName.getBytes();
                if (bytes[3] >= 65 && bytes[3] <= 90) {
                    bytes[3] += 32;
                }
                fieldName = new String(bytes, 3, bytes.length - 3);
            } else if (methodName.startsWith("is")) {
                byte[] bytes = methodName.getBytes();
                if (bytes[2] >= 65 && bytes[2] <= 90) {
                    bytes[2] += 32;
                }
                fieldName = new String(bytes, 2, bytes.length - 2);
            }
            if (fieldName == null) {
                throw new RuntimeException(String.format("unsupported method name %s", methodName));
            }
            return fieldName;
        } catch (NoSuchMethodException | SecurityException ex) {
            throw new RuntimeException("方法不存在", ex);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }



}
